/* eslint-disable @typescript-eslint/naming-convention */
import { generateKey } from 'crypto';
import { readlink } from 'fs';
import { normalize, resolve } from 'path';
import { listenerCount, nextTick } from 'process';
import { getEnabledCategories } from 'trace_events';
import * as vscode from 'vscode';

export class goDicSaveText {
    private doc: vscode.TextDocument;
    private diagnostics: vscode.Diagnostic[] = [];
    private gsDiagnostics: vscode.DiagnosticCollection;

    private keys: Map<string, any> = new Map<string, any>([
        ["import", 1],
        ["component", 1],
        ["public", 1],
        ["private", 1],
        ["void", 1],
        ["mixed", 1],
        ["object", 1],
        ["handle", 1],
        ["map", 1],
        ["array", 1],
        ["int", 1],
        ["int?", 1],
        ["float", 1],
        ["float?", 1],
        ["string", 1],
        ["bool", 1],
        ["bool?", 1],
        ["nil", 1],
        ["true", 1],
        ["false", 1],
        ["if", 1],
        ["else", 1],
        ["for", 1],
        ["do", 1],
        ["while", 1],
        ["continue", 1],
        ["break", 1],
        ["upto", 1],
        ["downto", 1],
        ["switch", 1],
        ["case", 1],
        ["default", 1],
        ["return", 1],
        ["readonly", 1],
        ["catch", 1],
        ["try_lock", 1],
        ["enum", 1],
        ["let", 1],
        ["export", 1],
        ["coroutine", 1],
        ["socket", 1],
        ["char", 1],
        ["long", 1],
        ["int64_t", 1],
        ["int32_t", 1],
        ["uint64_t", 1],
        ["uint32_t", 1],
        ["size_t", 1],
    ]);

    private elem = [
        {
            // 吸收空白字符
            "absorb" : function(text:string, start:number, range:vscode.Range):Map<string,any>|void{
                let subStr = text.substring(start);
                let s = subStr.trimStart();
                if (s.length === subStr.length) {
                    return;
                }

                let r = subStr.substring(0, subStr.length - s.length);
                return new Map<string, any>([
                    ["type", " "],
                    ["e", r],
                    ["len", r.length],
                    ["start", start],
                    ["range", range],

                    // 单空格，或者空格结束的位置是4的倍数都认为合法
                    ["check", function():boolean {
                        return r.length === 1 || (start + r.length) % 4 === 0;
                    }],
                ]);
            },
        },
        {
            // 吸收注释
            "absorb" : function(text:string, start:number, range:vscode.Range):Map<string,any>|void{
                let subStr = text.substring(start);
                if (subStr.startsWith("//")) {
                    // 单行注释
                    return new Map<string, any>([
                        ["type", "//"],
                        ["e", subStr],
                        ["len", subStr.length],
                        ["start", start],
                        ["range", range],
                    ]);
                } else if (subStr.startsWith("/*")) {
                    // 多行注释
                    let index = subStr.indexOf("*/", 2);
                    if (index < 0) {
                        // 未在本行结束的
                        return new Map<string, any>([
                            ["type", "/*"],
                            ["e", subStr],
                            ["len", subStr.length],
                            ["start", start],
                            ["range", range],
                            ["more", function(text:string):Map<string,any>|void{
                                let endIndex = text.indexOf("*/");
                                if (endIndex < 0) {
                                    return new Map<string, any>([
                                        ["type", "/*"],
                                        ["e", text],
                                        ["len", text.length],
                                        ["start", 0],
                                        ["end", false],
                                    ]);
                                }
                                let moreStr = text.substring(0, endIndex+2);
                                return new Map<string, any>([
                                    ["type", "/*"],
                                    ["e", moreStr],
                                    ["len", moreStr.length],
                                    ["start", 0],
                                    ["end", true],
                                ]);
                            }],
                        ]);
                    } else {
                        // 在本行结束的
                        return new Map<string, any>([
                            ["type", "/*"],
                            ["e", subStr.substring(0, index+2)],
                            ["len", index+2],
                            ["start", start],
                            ["range", range],
                        ]);
                    }
                } else {
                    return;
                }
            }
        },
        {
            // 吸收变量
            "absorb" : function(text:string, start:number, range:vscode.Range):Map<string,any>|void{
                let subStr = text.substring(start);
                let m = subStr.match(/^\w+/);
                if (!m) {
                    return;
                }
                let m1 = subStr.match(/^\w+\?/);
                if (m1 && ["int?", "float?", "bool?"].indexOf(m1[0]) >= 0) {
                    m = m1;
                }
                return new Map<string, any>([
                    ["type", "i"],
                    ["e", m[0]],
                    ["len", m[0].length],
                    ["start", start],
                    ["range", range],
                ]);
            }
        },
        {
            // 吸收宏
            "absorb" : function(text:string, start:number, range:vscode.Range):Map<string,any>|void{
                let subStr = text.substring(start);
                let m = subStr.match(/^#\S*/);
                if (!m) {
                    return;
                }
                return new Map<string, any>([
                    ["type", "#"],
                    ["e", m[0]],
                    ["len", m[0].length],
                    ["start", start],
                    ["range", range],
                ]);
            }
        },
        {
            // 吸收多行字符串
            "absorb" : function(text:string, start:number, range:vscode.Range):Map<string,any>|void{
                let subStr = text.substring(start);
                if (!subStr.startsWith("\"\"\"P")) {
                    return;
                }
                let index = subStr.indexOf("\"\"\"P", 4);
                if (index >= 0)
                {
                    return new Map<string, any>([
                        ["type", "\"\"\"P"],
                        ["e", text.substring(0, index + 4)],
                        ["len", index + 4],
                        ["start", start],
                        ["range", range],
                    ]);
                } else
                {
                    return new Map<string, any>([
                        ["type", "\"\"\"P"],
                        ["e", subStr],
                        ["len", subStr.length],
                        ["start", start],
                        ["range", range],
                        ["more", function(text:string):Map<string,any>|void{
                            let endIndex = text.indexOf("\"\"\"P");
                            if (endIndex < 0) {
                                return new Map<string, any>([
                                    ["type", "\"\"\"P"],
                                    ["e", text],
                                    ["len", text.length],
                                    ["start", 0],
                                    ["end", false],
                                ]);
                            }
                            let moreStr = text.substring(0, endIndex+4);
                            return new Map<string, any>([
                                ["type", "\"\"\"P"],
                                ["e", moreStr],
                                ["len", moreStr.length],
                                ["start", 0],
                                ["end", true],
                            ]);
                        }],
                    ]);
                }
            }
        },
        {
            // 吸收单行字符串
            "absorb" : function(text:string, start:number, range:vscode.Range):Map<string,any>|void{
                let subStr = text.substring(start);
                if (!subStr.startsWith("\"")) {
                    return;
                }
                let reverse = false;
                let i = 1;
                for (i; i < subStr.length; ++i) {
                    let c = subStr.charAt(i);
                    if (c === "\"" && !reverse)
                    {
                        break;
                    }

                    // 处理反斜杠
                    if (c === "\\") {
                        reverse = !reverse;
                    } else {
                        reverse = false;
                    }
                }
                return new Map<string, any>([
                    ["type", "\""],
                    ["e", text.substring(0, i + 1)],
                    ["len", i + 1],
                    ["start", start],
                    ["range", range],
                ]);
            }
        },
        {
            // 吸收字符
            "absorb" : function(text:string, start:number, range:vscode.Range):Map<string,any>|void{
                let subStr = text.substring(start);
                if (!subStr.startsWith("'")) {
                    return;
                }
                let reverse = false;
                let i = 1;
                for (i; i < subStr.length; ++i) {
                    let c = subStr.charAt(i);
                    if (c === "'" && !reverse)
                    {
                        break;
                    }

                    // 处理反斜杠
                    if (c === "\\") {
                        reverse = !reverse;
                    } else {
                        reverse = false;
                    }
                }
                return new Map<string, any>([
                    ["type", "'"],
                    ["e", text.substring(0, i + 1)],
                    ["len", i+1],
                    ["start", start],
                    ["range", range],
                ]);
            }
        },
        {
            // 吸收各种符号
            "absorb" : function(text:string, start:number, range:vscode.Range):Map<string,any>|void{
                let subStr = text.substring(start);
                let values = ["?.?", "?=>?", "?.", "?=>", ".?", "=>?", "??", "=>",
                    "==", "!=",
                    "..",
                    "(:", ":)",
                    "!!", "&&", "||",
                    "++", "--",
                    "<<=", ">>=",
                    "<<", ">>",
                    ">=", "<=",
                    "+=", "-=", "*=", "/=", "%=",
                    "&=", "|=", "^=",
                    ":=",
                    "?", ":", "+", "-", "*", "/", "%", "|", "&", "^", ",", "[", "]", "{", "}", "(", ")", "!", ".", ";", "=", "@",
                    ">", "<"
                ];
                for (let i in values) {
                    let e = values[i];
                    if (subStr.startsWith(e)) {
                        return new Map<string, any>([
                            ["type", "char"],
                            ["e", e],
                            ["len", e.length],
                            ["start", start],
                            ["range", range],
                        ]);
                    }
                }
                return;
            }
        },
        {
            "absorb" : function(text:string, start:number, range:vscode.Range):Map<string,any>|void{
                let subStr = text.substring(start);
                let m = subStr.match(/^\S+/);
                if (!m) {
                    return;
                }
                return new Map<string, any>([
                    ["type", "other"],
                    ["e", m[0]],
                    ["len", m[0].length],
                    ["start", start],
                    ["range", range],
                ]);
            }
        }
    ];

    constructor(doc: vscode.TextDocument, dc: vscode.DiagnosticCollection) {
        this.doc = doc;
        this.gsDiagnostics = dc;
    }

    private lines:Map<string,any>[] = [];

     // 当文件保存时做语法检测
    public OnSave()
    {
        if (this.doc.languageId !== "gs") {
            return;
        }
        let fileName = this.doc.fileName;
        let fm = fileName.match(/[^//\\]+$/);
        if (fm) {
            fileName = fm[0];
        }

        this.gsDiagnostics.delete(this.doc.uri);
        this.diagnostics = [];
        let more = null;
        let lines = [];
        for (let index = 0; index < this.doc.lineCount; index++) {
            let element = this.doc.lineAt(index);
            let ret = this.parseLine(index, element.text, more, element.range);
            let len = ret.get("elems").length;
            if (!more && len > 0) {
                more = ret.get("elems")[len - 1].get("more");
            } else if (more && len > 0) {
                let last = ret.get("elems")[len - 1];
                if (last.get("end") === true) {
                    more = null;
                } else if (last.get("end") === false) {
                    // empty
                } else {
                    more = null;
                }
            }
            lines.push(ret);
        }
        this.lines = lines;

        if (lines.length >= 3) {
            // 开头三行注释
            if (lines[0].get("type") !== "//" || this.doc.lineAt(0).text !== ("// " + fileName)) {
                this.addDiagnostic(lines[0].get("range"), "第一行应为" + "// " + fileName);
            }
            if (lines[1].get("type") !== "//" || !this.doc.lineAt(1).text.match(/Created by \S+ \d\d\d\d-\d{1,2}-\d{1,2}/)) {
                this.addDiagnostic(lines[1].get("range"), "第二行应为" + "// Created by author yyyy-mm-dd");
            }
            if (lines[2].get("type") !== "//") {
                this.addDiagnostic(lines[2].get("range"), "第三行应为文件功能描述");
            }
        }

        // 过滤开头的注释
        let index = 3;
        for (; index < lines.length; index++) {
            if (lines[index].get("type") !== "//") {
                break;
            }
        }

        let private_line_flag = false;
        let colon_lines = [];
        let last_line = null;
        let line;
        for (index; index < lines.length; index++) {
            line = lines[index];
            this.checkLine(line);
            if (last_line !== null) {
                if (line.get("type") === "" && last_line.get("type") === "") {
                    this.addDiagnostic(line.get("range"), "不能有连续的空行");
                } else if (line.get("type") === "function" &&
                    last_line.get("type") !== "//" &&
                    last_line.get("type") !== "/*" &&
                    (!last_line.get("end") || last_line.get("end").get("e") !== "}")) {
                    if (["create", "destruct", "main", "init", "boot", "import_cfg"].indexOf(line.get("name")) < 0 && !line.get("single_line")) {
                        this.addDiagnostic(line.get("range"), "函数需要注释");
                    }
                } else if (line.get("type") === "" && last_line.get("type") === "//") {
                    this.addDiagnostic(line.get("range"), "注释之后不能是空行");
                } else if (line.get("type") === "//" &&
                    ["//", "", "case", "if", "else", "default", "for", "while"].indexOf(last_line.get("type")) < 0 &&
                    ["{", ")"].indexOf(last_line.get("end").get("e")) < 0) {
                    this.addDiagnostic(line.get("range"), "注释前要空一行");
                }

                // 对 : 进行多行检查
                if (line.get("check:")) {
                    colon_lines.push(line);
                } else if (colon_lines.length > 0) {
                    this.checkColon(colon_lines);
                    colon_lines = [];
                }

                //
                if (!private_line_flag && line.get("type") === "function" &&
                    line.get("access") === "private" &&
                    ["create", "destruct", "main", "import_cfg"].indexOf(line.get("name")) < 0 &&
                    (!last_line.get("end") ||
                    last_line.get("end").get("e") !== "}"))
                {
                    // 开始 private 部分
                    private_line_flag = true;
                }

                if (private_line_flag && line.get("type") === "function" && line.get("access") !== "private")
                {
                    this.addDiagnostic(line.get("range"), "需要定义在private函数之前");
                }
            }

            last_line = line;
        }
        this.gsDiagnostics.set(this.doc.uri, this.diagnostics);
    }

    // 添加警告
    addDiagnostic(range:vscode.Range, message:string, severityType:vscode.DiagnosticSeverity = vscode.DiagnosticSeverity.Error)
    {
        let diagnostic: vscode.Diagnostic = new vscode.Diagnostic(range, message, severityType);
        diagnostic.source = 'gs语法规范检测';

        this.diagnostics.push(diagnostic);
    }

    // 添加警告
    addDiagnosticEx(m: RegExpExecArray, message:string, severityType:vscode.DiagnosticSeverity = vscode.DiagnosticSeverity.Error)
    {
        const range = new vscode.Range(this.doc.positionAt(m.index), this.doc.positionAt(m.index + m[0].length));
        this.addDiagnostic(range, `${m[0]} ${message}`, severityType);
    }

    // 解析单行
    parseLine(line_no:number, text:string, more:any, range:vscode.Range):Map<string, any> {
        let m = new Map<string, any>([
            ["no", line_no],
            ["elems", []],
            ["type", ""],
            ["range", range],
        ]);

        if (text.length === 0) {
            return m;
        }

        let left = null;
        let r;
        for (let start = 0; start < text.length;) {
            if (start === 0 && more) {
                r = more(text);
            } else
            {
                for (let e in this.elem) {
                    let absorb = this.elem[e]["absorb"];
                    r = absorb(text, start, range);
                    if (!r) {
                        continue;
                    }
                    if (r.get("type") === "i" && (left === null || left.get("e") !== ".")) {
                        // 关键字处理
                        let kv = this.keys.get(r.get("e"));
                        if (kv) {
                            r.set("key_word", kv);
                        }
                    }
                    break;
                }
            }

            if (!r) {
                continue;
            }

            start += r.get("len");
            let elems = m.get("elems");
            if (elems.length > 0)
            {
                let prev = elems[elems.length - 1];
                prev.set("next", r);
                r.set("prev", prev);
            }
            elems.push(r);
            if (m.get("type") === "")
            {
                // 确定是本行是什么内容
                switch (r.get("e")) {
                    case "void":
                    case "public":
                    case "private":
                        if (text.indexOf("(") >= 0) {
                            m.set("type", "function");
                            m.set("access", r.get("e"));
                        } else {
                            m.set("type", "i");
                        }
                        break;
                    default:
                        if (["if", "else", "case", "default"].indexOf(r.get("e")) >= 0) {
                            m.set("type", r.get("e"));
                        } else if (r.get("type") !== " ") {
                            m.set("type", r.get("type"));
                        }
                }
            } else if (m.get("type") === "function" && !m.get("name") && r.get("type") !== " " && !r.get("key_word")) {
                m.set("name", r.get("e"));
            }

            //
            left = r;
        }

        // 单行函数
        if (m.get("type") === "function" && r.get("e") === "}") {
            m.set("single_line", true);
        }

        m.set("end", r);
        return m;
    }

    checkLine(line:Map<string, any>) {
        let elems = line.get("elems");
        let len = elems.length;
        if (len === 0) {
            return;
        }

        let end = elems[len - 1];
        if (end.get("type") === " ") {
            // 行尾不允许有空格
            this.addDiagnostic(end.get("range"), "行尾不允许有空格");
            return;
        }

        if (elems[0].get("type") === " " && (elems[0].get("e") === " " || !elems[0].get("check")())) {
            this.addDiagnostic(elems[0].get("range"), "行首缩进不对");
            return;
        }

        let left = null;
        let right = null;

        // 左侧最后一个非空格的元素
        let left_ex = null;

        for (let i = 0; i < len; ++i) {
            let e = elems[i];
            let c = e.get("e");

            if (i + 1 < len) {
                right = elems[i + 1];
            } else {
                right = null;
            }
            if (e.get("type") === "char") {
                switch (c) {
                    case "--": case "++":
                        if (left_ex !== null && left_ex.get("type") === "i" && left.get("type") === " ") {
                            this.addDiagnostic(e.get("range"), c + "左侧不能有空格");
                            return;
                        }
                        if (right !== null && right.get("type") === " ") {
                            let right_ex = right.get("next");
                            if (right_ex.get("type") === "i") {
                                this.addDiagnostic(e.get("range"), c + "右侧不能有空格");
                                return;
                            }
                            if ([")", ";"].indexOf(right.get("next").get("e")) >= 0) {
                                this.addDiagnostic(e.get("range"), c + "右侧不能有空格");
                                return;
                            }
                        }
                        break;
                    case "?.?": case "?=>?": case "?.": case "?=>": case ".?": case "=>?": case "=>": case ".":
                        // 左右都不能有空格的
                        if (left !== null && left.get("type") === " ") {
                            if (c !== "." && left_ex.get("e") !== "import") {
                                this.addDiagnostic(e.get("range"), c + "左侧不能有空格");
                                return;
                            }
                        }
                        if (right !== null && right.get("type") === " ") {
                            this.addDiagnostic(e.get("range"), c + "右侧不能有空格");
                            return;
                        }
                        break;
                    case "??": case "==": case "!=": case "&&": case "||": case "<<=": case ">>=": case "<<": case ">>": case "+=":
                    case "-=": case "*=": case "/=": case "%=": case "&=": case "|=": case "^=": case ":=": case "=": case "..":
                    case "?": case "+": case "-": case "*": case "/": case "%": case "|": case "&": case "^":
                    case "<": case "<=": case ">": case ">=":
                        if (c === "-") {
                            if (left_ex !== null && left_ex.get("type") === "i" && !left_ex.get("key_word")) {
                                // a - b 形式，说明是减号。break 走下面的逻辑
                            } else
                            {
                                if (right !== null && right.get("type") === " " && [")", "]"].indexOf(left_ex.get("e")) < 0) {
                                    this.addDiagnostic(e.get("range"), c + "右侧不能有空格");
                                    return;
                                }
                                break;
                            }
                        } else if (c === "..") {
                            // 不处理吧
                            break;
                        } else if (c === "<" && (left_ex.get("e") === ".." || left_ex.get("e") === "[")) {
                            // 不处理吧
                            break;
                        } else if (c === "*" && left.get("e") === ".") {
                            break;
                        }

                        // 左右都要有空格的
                        if (left === null || (left.get("type") !== " " && left.get("e") !== "[")) {
                            if (c !== "?" || left.get("e").toUpperCase() !== left.get("e"))
                            {
                                this.addDiagnostic(e.get("range"), c + "左侧要有空格");
                            }
                            return;
                        } else if (left.get("type") === " " && !left.get("check")()) {
                            if (!this.checkNeighborLineSpace(line, e, null, c, true, false)) {
                                this.addDiagnostic(e.get("range"), c + "左侧空格数量不对");
                            }
                            return;
                        }

                        if (right === null) {
                            // empty
                        } else if (right.get("type") !== " " && right.get("e") !== "]") {
                            if (!this.isCPtr(c, left_ex)) {
                                this.addDiagnostic(e.get("range"), c + "右侧要有空格");
                            }
                            return;
                        } else if (right.get("type") === " " && !right.get("check")()) {
                            this.addDiagnostic(e.get("range"), c + "右侧空格数量不对");
                            return;
                        }
                        break;
                    case ":":
                        if (elems[1].get("e") === "case") {
                            if (left.get("type") === " ") {
                                this.addDiagnostic(e.get("range"), "正确的格式应为case x:");
                            }
                            return;
                        } else if (left_ex.get("e") === "new") {
                            break;
                        } else if (left_ex.get("e") === "default") {
                            if (left.get("type") === " ") {
                                this.addDiagnostic(e.get("range"), "正确的格式应为default:");
                            }
                            return;
                        }

                        if (right === null) {
                            // empty
                        } else if (!line.get("check:")) {
                            // 多行看不合法。打上标志，多行检查。
                            line.set("check:", {
                                "e" : e,
                                "left" : left,
                                "left_ex" : left_ex,
                                "right" : right,
                            });
                        }
                        break;
                    case ":)":
                        // 左边有空格的
                        if (left === null || left.get("type") !== " ") {
                            this.addDiagnostic(e.get("range"), c + "左侧要有空格");
                            return;
                        } else if (!left.get("check")()) {
                            this.addDiagnostic(e.get("range"), c + "左侧空格数量不对");
                            return;
                        }
                        break;
                    case "(:":
                        // 右边有空格的
                        if (right === null || right.get("type") !== " ") {
                            this.addDiagnostic(e.get("range"), c + "右侧要有空格");
                            return;
                        } else if (!right.get("check")()) {
                            this.addDiagnostic(e.get("range"), c + "右侧空格数量不对");
                            return;
                        }
                        break;
                    case "(": case "!": case "!!": case "[":
                        if (right !== null && right.get("type") === " ") {
                            this.addDiagnostic(e.get("range"), c + "右侧不能有空格");
                            return;
                        } else if (left_ex !== null && left_ex.get("type") === "i" && !left_ex.get("key_word") && left.get("type") === " ") {
                            if (!this.isMacro(line)){
                                this.addDiagnostic(e.get("range"), c + "左侧不能有空格");
                            }
                            return;
                        }
                        break;
                    case ")": case ";": case ",":
                        if (left !== null && left.get("type") === " " && this.prevSymbol(left)) {
                            this.addDiagnostic(e.get("range"), c + "左侧不能有空格");
                            return;
                        }
                        if (c === "," && right !== null) {
                            // 右边有空格的
                            if (right.get("type") !== " ") {
                                this.addDiagnostic(e.get("range"), c + "右侧要有空格");
                                return;
                            } else if (!right.get("check")()) {
                                if (!this.checkNeighborLineSpace(line, right, right.get("type"), null, false, true)) {
                                    this.addDiagnostic(e.get("range"), c + "右侧空格数量不对");
                                }
                                return;
                            }
                        } else if (c === ";") {
                            if (!left_ex) {
                                this.addDiagnostic(e.get("range"), c + "左侧缺少return?");
                                return;
                            }
                            if ([")", "return", "continue", "]", "}", "break"].indexOf(left_ex.get("e")) < 0) {
                                let prev = this.prevSymbol(left_ex);
                                if (!prev) {
                                    this.addDiagnostic(e.get("range"), left_ex.get("e") + "左侧缺少return?");
                                    return;
                                }
                            }
                        }
                        break;
                    case "{":
                        if (right !== null) {
                            if (right.get("type") === " ") {
                                let  right_ex = right.get("next");
                                if (!right.get("check")()) {
                                    this.addDiagnostic(e.get("range"), c + "右侧空格数量不对");
                                    return;
                                }
                                if (right_ex !== null && !right_ex.get("key_word") && (right_ex.get("type") === "i" || right_ex.get("type") === "\"")) {
                                    this.addDiagnostic(e.get("range"), c + "右侧不能有空格");
                                    return;
                                }
                            }
                        }
                        break;
                    case "}":
                        if (left_ex !== null) {
                            if (left_ex.get("e") === "{") {
                                if (left.get("type") === " ") {
                                    this.addDiagnostic(e.get("range"), "空map应书写成{}");
                                    return;
                                }
                            } else if (this.findPrevElem(left_ex, "return", "{")) {
                                if (left.get("type") !== " ") {
                                    this.addDiagnostic(e.get("range"), c + "左侧要有空格");
                                    return;
                                }
                            } else if (left.get("type") === " ") {
                                this.addDiagnostic(e.get("range"), c + "左侧不能有空格");
                                return;
                            }
                        }
                        break;
                }
            } else if (e.get("key_word")) {
                if (["for", "if", "while", "else"].indexOf(e.get("e")) >= 0 && end.get("e") === "{" && !this.checkPrev(end, ",", true)) {
                    this.addDiagnostic(e.get("range"), c + "的{要另起一行");
                    return;
                }

                // if (expre);
                if (["for", "if", "while", "else"].indexOf(e.get("e")) >= 0 && end.get("e") === ";") {
                    let prev = this.prevSymbol(end);
                    if (prev) {
                        if (prev.get("e") === ")") {
                            let symbol = this.prevSymbol(this.matchLeftSymbol(prev));
                            if (symbol && symbol.get("e") === e.get("e") && left_ex.get("e") !== "}" && left_ex.get("e") !== "do") {
                                this.addDiagnostic(e.get("range"), c + "非预期的;号");
                                return;
                            }
                        }
                        if (["return", "continue", "break"].indexOf(prev.get("e")) >= 0) {
                            break;
                        }
                        let prev2 = this.prevSymbol(prev);
                        if (!prev2 || prev2.get("e") === ")") {
                            let symbol = prev2 ? this.prevSymbol(this.matchLeftSymbol(prev2)) : null;
                            if (symbol && symbol.get("e") === e.get("e")) {
                                this.addDiagnostic(e.get("range"), prev.get("e") + "左侧缺少return?");
                                return;
                            }
                        }
                    }
                }

                if (c === "import") {
                    let packet_name = this.prevSymbol(end);
                    if (packet_name && ["*", "preimport", "scripts", "efun"].indexOf(packet_name.get("e")) < 0) {
                        let math_str = packet_name.get("e");
                        let math_strs = [math_str];
                        if (math_str === "configd") {
                            math_strs = [math_str, "IS_GS"];
                        } else if (math_str === "health") {
                            math_strs = [math_str, "HEALTH"];
                        } else if (math_str === "micro_serverd") {
                            math_strs = [math_str, "HAS_MS"];
                        } else if (math_str === "keep") {
                            math_strs = [math_str, "KEEP"];
                        } else if (math_str === "formulad") {
                            math_strs = [math_str, "FI"];
                        } else if (math_str === "gdd") {
                            math_strs = [math_str, "GD"];
                        }
                        let index = -1;
                        for (let s of math_strs) {
                            index = this.doc.getText().indexOf(s);
                            if (index && index >= 0 && s === math_str)
                            {
                                index = this.doc.getText().indexOf(s, index + 1);
                                if (index && index >= 0) {
                                    break;
                                }
                            }
                        }

                        if (!index || index < 0) {
                            this.addDiagnostic(e.get("range"), c + "了未使用的模块");
                            return;
                        }
                    }
                }

                // 关键字处理
                if (c === "try_lock" || c === "catch") {
                    if (right !== null && right.get("type") === " ") {
                        this.addDiagnostic(e.get("range"), c + "右侧不能有空格");
                        return;
                    }
                } else if (c === "return") {
                    if (right !== null && right.get("type") !== " " && right.get("e") !== ";") {
                        this.addDiagnostic(e.get("range"), c + "右侧需要有空格");
                        return;
                    } else if (right !== null && right.get("e") !== " " && right.get("e") !== ";") {
                        this.addDiagnostic(e.get("range"), c + "右侧空格数量不对");
                        return;
                    } else if (left_ex !== null && left_ex.get("e") === ")" && (left.get("type") !== " " || !left.get("check")())) {
                        this.addDiagnostic(e.get("range"), c + "右侧空格数量不对");
                        return;
                    }
                } else if (c === "default") {
                    if (right.get("e") !== ":") {
                        this.addDiagnostic(e.get("range"), "正确的格式应为default:");
                        return;
                    }
                } else if (right !== null) {
                    if (right.get("e") === "*" && (e.get("type") === "i" || e.get("e") === "*")) {
                        return;
                    }
                    if (right.get("type") !== " " && [")", ";", ",", ".", "[", "}", "]"].indexOf(right.get("e")) < 0) {
                        this.addDiagnostic(e.get("range"), c + "右侧要有空格");
                        return;
                    } else if (right.get("type") === " " && !right.get("check")()) {
                        if (!this.checkNeighborLineSpace(line, right, right.get("type"), null, false, true)) {
                            this.addDiagnostic(e.get("range"), c + "右侧空格数量不对");
                        }
                        return;
                    }
                }
            } else if (e.get("type") === "//") {
                if (!e.get("e").match(/^\/\/ /)) {
                    this.addDiagnostic(e.get("range"), "注释的格式应为// 注释内容");
                    return;
                }
            }else if (e.get("type") === "i") {
                if (left_ex !== null && left_ex.get("e") === ")" && left.get("type") === " " && ["int", "map", "float", "bool"].indexOf(elems[i - 3].get("e")) >= 0) {
                    this.addDiagnostic(e.get("range"), "类型强转格式应为(type)i");
                    return;
                }
            }

            left = e;
            if (e.get("type") !== " ") {
                left_ex = e;
            }
        }
    }

    // 检查冒号的空格
    checkColon(lines:any[]) {
        let m = new Map<number, any>();
        let f = true;
        for (let i = 0; i < lines.length; ++i) {
            let line = lines[i];
            let e = line.get("check:")["e"];
            let index:number = e.get("start");
            if (m.get(index) || i === 0) {
                m.set(index, true);
            } else {
                m.set(index, line);
                f = false;
            }
        }
        if (f) {
            return;
        }

        let m2 = new Map<number, any>();
        let f2 = true;
        for (let i = 0; i < lines.length; ++i) {
            let line = lines[i];
            let right = line.get("check:")["right"];
            let index:number = right.get("start") + right.get("len");
            if (m2.get(index) || i === 0) {
                m2.set(index, true);
            } else {
                m2.set(index, line);
                f2 = false;
            }
        }
        if (f2) {
            return;
        }

        for (let line of m.values()) {
            if (line === true) {
                continue;
            }
            let e = line.get("check:")["e"];
            let left = line.get("check:")["left"];
            let right = line.get("check:")["right"];
            if (left.get("type") !== " " || !left.get("check")()) {
                this.addDiagnostic(e.get("range"), ":左侧的空格数量不正确");
            } else if (right.get("type") !== " " || !right.get("check")()) {
                this.addDiagnostic(e.get("range"), ":右侧的空格数量不正确");
            }
        }
    }

    // 检测下一个元素
    checkNext(e :Map<string, any>, c:string, ignore_space :boolean) :boolean {
        let next = e.get("next");
        if (!next) {
            return c === null;
        }
        if (next.get("type") !== " " || c === " ") {
            return next.get("e") === c;
        }
        if (!ignore_space) {
            return false;
        }
        next = next.get("next");
        if (!next) {
            return false;
        }
        return next.get("e") === c;
    }

    // 检测上一个元素
    checkPrev(e :Map<string, any>, c:string, ignore_space :boolean) :boolean {
        let prev = e.get("prev");
        if (!prev) {
            return c === null;
        }
        if (prev.get("type") !== " " || c === " ") {
            return prev.get("e") === c;
        }
        if (!ignore_space) {
            return false;
        }
        prev = prev.get("prev");
        if (!prev) {
            return false;
        }
        return prev.get("e") === c;
    }

    findPrevElem(e :Map<string, any>|void, c:string, end:string) :boolean {
        while (e) {
            if (e.get("e") === end) {
                return false;
            }
            if (e.get("e") === c) {
                return true;
            }
            e = this.prevSymbol(e);
        }
        return false;
    }

    // 上一个非空符号
    prevSymbol(e :Map<string, any>|void) :Map<string, any>|void {
        if (!e) {
            return;
        }
        let prev = e.get("prev");
        if (!prev) {
            return;
        }
        if (prev.get("type") !== " ") {
            return prev;
        }
        prev = prev.get("prev");
        if (!prev) {
            return;
        }
        return prev;
    }

    // 匹配符号
    matchRightSymbol(e :Map<string, any>|void) :Map<string, any>|void {
        if (!e) {
            return;
        }
        let s = "";
        switch (e.get("e")) {
            case "(": s = ")"; break;
            case "{": s = "}"; break;
            case "[": s = "]"; break;
        }
        let count = 1;
        let next = e.get("next");
        while (next)
        {
            if (next.get("e") === s) {
                count--;
                if (count === 0) {
                    return next;
                }
            } else if (next.get("e") === e.get("e")) {
                count++;
            }
            next = next.get("next");
        }
        return;
    }

    // 匹配符号
    matchLeftSymbol(e :Map<string, any>|void) :Map<string, any>|void {
        if (!e) {
            return;
        }
        let s = "";
        switch (e.get("e")) {
            case ")": s = "("; break;
            case "}": s = "{"; break;
            case "]": s = "["; break;
        }
        let count = 1;
        let prev = e.get("prev");
        while (prev)
        {
            if (prev.get("e") === s) {
                count--;
                if (count === 0) {
                    return prev;
                }
            } else if (prev.get("e") === e.get("e")) {
                count++;
            }
            prev = prev.get("prev");
        }
        return;
    }

    // 检查相邻行的空格
    checkNeighborLineSpace(line:Map<string, any>, e:Map<string, any>, t:any, c:any, checkStart:boolean, checkEnd:boolean) :boolean{
        let start:number = e.get("start");
        let end:number = start + e.get("len");
        let no = line.get("no");
        if (no > 1) {
            let prev_line = this.lines[no - 1];

            if (this.matchElemStart(prev_line, start, end, t, c, checkStart, checkEnd)) {
                return true;
            }
        }

        if (no < this.lines.length - 1) {
            let next_line = this.lines[no + 1];
            if (this.matchElemStart(next_line, start, end, t, c, checkStart, checkEnd)) {
                return true;
            }
        }
        return false;
    }
    matchElemStart(line:Map<string, any>, start:number, end:number, t:any, c:any, checkStart:boolean, checkEnd:boolean) :boolean{
        for (const elem of line.get("elems")) {
            if (t && t !== elem.get("type")) {
                continue;
            }
            if (c && c !== elem.get("e")) {
                continue;
            }
            let s:number = elem.get("start");
            let len:number = elem.get("len");
            if (checkStart && s === start) {
                return true;
            }
            if (checkEnd && s + len === end) {
                return true;
            }
        }
        return false;
    }

    // 是否为c语言的指针声明
    isCPtr(c:any, left_ex:any) :boolean{
        if (!c || !left_ex) {
            return false;
        }
        if (c !== "*") {
            return false;
        }
        let key_word = left_ex.get("key_word");
        if (!!key_word || left_ex.get("e") === "*"){
            return true;
        }
        let prev = this.prevSymbol(left_ex);
        if (prev && prev.get("e") === "struct") {
            return true;
        }
        return false;
    }

    // 是否为宏定义
    isMacro(line:Map<string, any>) :boolean{
        for (const elem of line.get("elems")) {
            if (elem.get("e") === "#define") {
                return true;
            }
        }
        return false;
    }
}
